package org.finesys.common.netty.websocket.handler;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.*;
import org.finesys.common.netty.websocket.support.WebSocketEndpointEventServer;

/**
 * 自定义处理消息
 */
public class WebSocketServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    private final WebSocketEndpointEventServer webSocketEndpointEventServer;

    public WebSocketServerHandler(WebSocketEndpointEventServer webSocketEndpointEventServer) {
        // 将传入的 WebSocketEndpointEventServer 对象赋值给当前对象的 webSocketEndpointEventServer 属性
        this.webSocketEndpointEventServer = webSocketEndpointEventServer;
    }


    /**
     * 接收消息
     *
     * @param ctx ChannelHandlerContext
     * @param msg WebSocketFrame
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
        // 调用 handleWebSocketFrame 方法处理 WebSocket 帧
        handleWebSocketFrame(ctx, msg);
    }


    /**
     * 处理错误
     *
     * @param ctx   ChannelHandlerContext
     * @param cause Throwable
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 调用WebSocket端点事件服务器的doOnError方法，处理异常
        webSocketEndpointEventServer.doOnError(ctx.channel(), cause);
    }


    /**
     * 关闭非活动连接
     * <p>
     * 当通道变为非活动状态时，此方法会被调用，用于关闭与WebSocket端点的连接。
     *
     * @param ctx ChannelHandlerContext 通道处理器上下文，包含了通道的状态和操作接口
     * @throws Exception 如果在关闭连接过程中发生异常，则会抛出该异常
     */

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 调用WebSocket端点事件服务器的doOnClose方法，通知WebSocket端点关闭连接
        webSocketEndpointEventServer.doOnClose(ctx.channel());
    }


    /**
     * 处理用户事件触发
     *
     * 当Netty检测到某些用户事件时，会调用此方法。
     *
     * @param ctx ChannelHandlerContext 通道处理器上下文，提供了对Netty通道及其配置的操作
     * @param evt Object 用户事件对象，具体内容取决于事件类型
     * @throws Exception 如果在处理过程中发生异常，则抛出
     */
    /**
     * heartbeat
     *
     * @param ctx ChannelHandlerContext
     * @param evt Object
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 调用WebSocket端点事件服务器的doOnEvent方法，处理用户事件
        webSocketEndpointEventServer.doOnEvent(ctx.channel(), evt);
    }


    /**
     * 处理不同类型的WebSocket帧
     *
     * @param ctx   ChannelHandlerContext
     * @param frame WebSocketFrame
     */
    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        // 如果帧是TextWebSocketFrame类型
        if (frame instanceof TextWebSocketFrame) {
            // 调用WebSocket端点事件服务器的doOnMessage方法处理文本消息
            webSocketEndpointEventServer.doOnMessage(ctx.channel(), frame);
            return;
        }
        // 如果帧是BinaryWebSocketFrame类型
        if (frame instanceof BinaryWebSocketFrame) {
            // 调用WebSocket端点事件服务器的doOnBinary方法处理二进制消息
            webSocketEndpointEventServer.doOnBinary(ctx.channel(), frame);
            return;
        }
        // 如果帧是PingWebSocketFrame类型
        if (frame instanceof PingWebSocketFrame) {
            // 发送PongWebSocketFrame作为响应
            ctx.writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        // 如果帧是CloseWebSocketFrame类型
        if (frame instanceof CloseWebSocketFrame) {
            // 发送关闭帧并关闭通道
            ctx.writeAndFlush(frame.retainedDuplicate()).addListener(ChannelFutureListener.CLOSE);
            return;
        }
        // 如果帧是PongWebSocketFrame类型，则直接返回，不处理
        if (frame instanceof PongWebSocketFrame) {
            return;
        }
    }

}
